package com.hwq.sql.script.utils;

import com.hwq.sql.script.exception.ServerException;
import com.hwq.sql.script.model.vo.ResultVO;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.InetAddress;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.util.Objects;

public class HttpUtil {

    /**
     * 获取 HTTP 请求对象
     */
    public static HttpServletRequest getReq() {
        RequestAttributes holder = RequestContextHolder.getRequestAttributes();
        return ((ServletRequestAttributes) Objects.requireNonNull(holder)).getRequest();
    }

    /**
     * 获取 HTTP 响应对象
     */
    public static HttpServletResponse getRes() {
        RequestAttributes holder = RequestContextHolder.getRequestAttributes();
        return ((ServletRequestAttributes) Objects.requireNonNull(holder)).getResponse();
    }

    /**
     * 获取请求头中的内容
     */
    public static String getHeader(String key) {
        HttpServletRequest req = getReq();
        return req.getHeader(key);
    }

    /**
     * 获取发送请求的客户端 真实主机地址
     */
    public static String getIpHost() {
        HttpServletRequest req = getReq();
        try {
            String ipAddress = req.getHeader("x-forwarded-for");
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = req.getHeader("Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = req.getHeader("WL-Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = req.getRemoteAddr();
            }
            if ("127.0.0.1".equals(ipAddress) || "0:0:0:0:0:0:0:1".equals(ipAddress)) {
                InetAddress inet = InetAddress.getLocalHost();
                ipAddress = inet.getHostAddress();
            }
            if (ipAddress != null && ipAddress.length() > 15 && ipAddress.indexOf(",") > 0) {
                ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
            }
            return ipAddress;
        } catch (UnknownHostException ex) {
            throw new ServerException(ex);
        }
    }

    /**
     * 返回响应结果
     * @param status 响应码对象
     * @param msg    响应信息
     * @param data   响应数据
     */
    public static <T> ResultVO<T> result(HttpStatus status, String msg, T data) {
        ResultVO<T> vo = new ResultVO<>();
        vo.setCode(status.value());
        vo.setMsg(msg);
        vo.setData(data);
        return vo;
    }

    /**
     * 返回成功的响应结果
     * @param msg  响应信息
     * @param data 响应数据
     */
    public static <T> ResultVO<T> success(String msg, T data) {
        return result(HttpStatus.OK, msg, data);
    }

    /**
     * 返回成功的响应结果
     * @param msg 响应信息
     */
    public static <T> ResultVO<T> success(String msg) {
        return success(msg, null);
    }

    /**
     * 返回失败的响应结果（客户端异常）
     * @param msg 响应信息
     * @param data 响应数据
     */
    public static <T> ResultVO<T> failure(String msg, T data) {
        return result(HttpStatus.BAD_REQUEST, msg, data);
    }

    /**
     * 返回失败的响应结果（客户端异常）
     * @param msg 响应信息
     */
    public static <T> ResultVO<T> failure(String msg) {
        return failure(msg, null);
    }

    /**
     * 返回失败的响应结果（服务端异常）
     * @param msg 响应信息
     * @param data 响应数据
     */
    public static <T> ResultVO<T> error(String msg, T data) {
        return result(HttpStatus.INTERNAL_SERVER_ERROR, msg, data);
    }

    /**
     * 返回失败的响应结果（服务端异常）
     * @param msg 响应信息
     */
    public static <T> ResultVO<T> error(String msg) {
        return error(msg, null);
    }

    /**
     * 下载文件，任意类型的文件，都会触发下载，注意 文件名后缀要和文件类型 对应好
     * @param fileName 文件名称
     * @param bytes    文件的二进制数据
     */
    public static void attachment(String fileName, byte[] bytes) {
        HttpServletResponse res = HttpUtil.getRes();
        try {
            res.setHeader("Content-Type", MediaType.APPLICATION_OCTET_STREAM_VALUE);
            res.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
            ServletOutputStream outputStream = res.getOutputStream();
            outputStream.write(bytes);
            outputStream.flush();
        } catch (IOException ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex.getMessage());
        }
    }

    /**
     * 返回文件为预览模式，需要浏览器支持
     */
    public static void inline(String fileType, String fileName, byte[] bytes) {
        HttpServletResponse res = HttpUtil.getRes();
        try {
            res.setHeader("Content-Type", fileType);
            res.setHeader("Content-Disposition", "inline;filename=" + URLEncoder.encode(fileName, "utf-8"));
            ServletOutputStream outputStream = res.getOutputStream();
            outputStream.write(bytes);
            outputStream.flush();
        } catch (IOException ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex.getMessage());
        }
    }

    /**
     * 返回 PDF 文件，浏览器可以直接预览
     * @param fileName 文件名称
     * @param bytes    文件的二进制数据
     */
    public static void inlinePdf(String fileName, byte[] bytes) {
        inline(MediaType.APPLICATION_PDF_VALUE, fileName, bytes);
    }

    /**
     * 返回 JPEG 文件，浏览器可以直接预览
     * @param fileName 文件名称
     * @param bytes    文件的二进制数据
     */
    public static void inlineJpeg(String fileName, byte[] bytes) {
        inline(MediaType.IMAGE_JPEG_VALUE, fileName, bytes);
    }

}
